<?
/*** Небольшая библиотека работы с возвратными URL 


	Возратный URL - это адрес страницы, который запоминается, и куда нужно вернуться после совершения каких-то действий на одной или нескольких других страницах. 

	Примеры ситуаций, когда необходим возврат:
		- неавторизованый админ запрашивает страницу админки, система редиректит его на форму авторизации (с постоянным URL /admin/login/ ), и после успешной авторизации его нужно вернуть на первоначально запрошеную старницу админки
		- в файл-менеджере посетитель смотрит список файлов, отфильтрованный по папке и подстроке, он нажимает ссылку удалить / переименовать / редактировать - и после совершения действия система должан переадресовать его братно на ту же выдорку, папку и фильтр
		- админ находиться на сайте и нажимает на ссылку "редактировать" около статьи - перходит в админку, в форму редактирования статьи, и тепереь после нахажития кнопки "Отмена" или кнопки "Сохранить и выйти", должен вернуться на прежнюю страницу сайта	
		
		Важное условие: возвратный URL может быть различный для различных окон (или вкладок) браузера. Например, в одной вкладке мы открываем форму редактирования статьи и возвратный URL для этой формы - страница на сайте, а в другой вкладке открываем форму редактирования статьи , перейдя на неё из страницы админки - из списка статей с фильтрацией по категории, в третьей вкладке - редактируем файл-изображение, перейдя на эту форму из админки, из списка файлов.
Ещё в одно вкладке - отображается выборка статей по набору параметров, и при нажатии на сссылки удалить/переименовать/выключить - должен вызываться другой URL , чтобы выполнить действия, и потом должен происходить редирект обратно на исходную выборку статей (причем без кеширования). Аналогично такойже URL-действия (с редиректом обратно) может быть вызвать из сайта (админом или пользователем с правами редактора). 		
Каждая из этих форм / страниц-действий должна знать свой возвратный URL (получил его из GET / POST / COOKIE) и использовать его при нажатии кнокпи "Отмена" или "Сохранить и выйти".  		
	Так что, поскольку должна быть возмоность сохранять разные возратные адреса для разных вкладок, то их нельзя передавать чреез COOKIE (чтобы они не затирали друг друга), либо же использовать COOKIE очень ограниченно и очень быстро:  записал в куку - редирект на фикироаный URL - прочитал из куки - очистил куку. 

	
	Примеры использования техники возвратного адреса: 

1)  Доступ неавторизованого пользователя к защищенной странице: 
	

	if(!$User->is_admin) ReturnURL::reject('/admin/login');
	
	Здесь произойдет редирект на неизменный URL с быстрой передачей ReturnURL через куку.

2) В форме авторизации:
   
	<input type=hidden name='<?=ReturnURL::$name ?>' value='<?=ReturnURL::$url ?>' >
	
	В этой форме ReturnURL::$url будет пустой при прямом доступе к станице авторизации. Обработчик авторизации, после успешного логина должен сделать редирект, с указанием дефолтной страницы:
	
	RetunURL::redirect('/admin/');
	
	
3) Ссылка на редактирование страницы: 

	<a href=/admin/site/edit_page/<?=$id?>/?<?=ReturnURL::$suffix ?> >
	

	
***/




ReturnURL::init();

class ReturnURL {
	
	// имя переменной для передачи через GET / POST / COOKIE
	static $name = 'return_url';
	
	static 	$url; 	// ReturnURL:$url - собственно значение ReturnURL, подхваченое из GET / POST (и иногда из Cookie)
	
	static 	$suffix,	// суффикс для URL вида  'return_url=/return/url/'
			$suffix1, 	// суффикс для URL вида  '?return_url=/return/url/'
			$suffix2 ;	// суффикс для URL вида  '&return_url=/return/url/'
	
	
	// инициализирует ReturnURL - назначает ему адрес переданный через GET/POST, или сохраненный ранее в COOKIE / SESSION, или (если не назначен) - адрес текущей страницы
	// (значение ReturnURL::$url будет использоваться в дальнейшем для формирования ссылок или для возратного редиректа)
	static function init()
	{
		
		//pr('1---',$_POST);
		
		// определяем - был ли передан ReturnURL ?
			($url = val($_GET	[self::$name ]))
		OR	($url = val($_POST	[self::$name ]))
		
		//echo 1;
		
		
		// определяем - был ли сохранен ранее ReturnURL ?
		// (но это не работает, при работе в нескольких вкладках браузера) 
		//OR	($url = 	 val($_SESSION	[self::$name]))
		OR	($url = trim(val($_COOKIE	[self::$name])))
		
		// иначе - используем текущий адрес
		OR 	($url = $_SERVER['REQUEST_URI'])
		;
		
		//pr($_POST);
		
		// очищаем сохраненный в куках кратковременный ReturnURL
		setcookie(self::$name , ' ', 0, '/');
		
		// инициализируем свойства RetunURL
		self::set_return_properties($url);
		
		//pr(ReturnURL::$url);
	}
	
	// инициализирует все свойства для испльзования RetunURL
	static function set_return_properties($url)
	{
		//echo "*";
		// если это адрес текущей страницы, то НЕ назначаем основной возвратный URL
		if($url!= $_SERVER['REQUEST_URI'])
			self::$url = $url;
		
		// но суффиксы для ссылок вычисляем даже если возвратный URL - это текущий адрес
		self::$suffix 	= self::$name .'=' . urlencode($url);
		self::$suffix1 	= '?' . self::$suffix;
		self::$suffix2 	= '&' . self::$suffix;
	}
	
	// static function get(){return self::$url;}
	// static function value(){return self::$url;}
	
	
	// фиксирует текущий адрес страницы - как ReturnURL (возратный URL) - в куках и сессии, так что с этого момента при переходе по ссылке он будет передан другой странице через COOKIE и SESSION (при условии, что он не будет установлен в другом окне браузера)
	static function set()
	{
		
		$url = $_SERVER['REQUEST_URI'];
		
		self::set_return_properties($url);
		
		//$_COOKIE[self::$name] = $url;
		//setcookie(self::$name , $url, 0, '/');
		
		//if (isset($_SESSION)) $_SESSION[self::$name] = $url;
		
	}
	
	// обнуляет сохраненный ReturnURL и возвращает режим, когда он берется из текущего адреса
	static function reset()
	{
		// очищаем сохраненный в куках и сессии ReturnURL
		setcookie(self::$name , ' ', 0, '/');
		//if (isset($_SESSION)) $_SESSION[self::$name] = '';
		
		// устанавливает текущий url как ReturnURL
		self::set_return_properties($_SERVER['REQUEST_URI']);
		
	}
	
	// редиректит на указанный URL, фикируя текущий URL как возвратный 
	static function reject($url, $time=0)
	{
		setcookie(self::$name ,$_SERVER['REQUEST_URI'], 0, '/');
		Cache::nocache_headers();
		redirect($url, $time ? $time : 0.1); // устанавливаем ненулевое время, чтобы редирект был сделать через метатег, чтобы кука смогла вернуться на сервер
	}
	
	// редиректит на ReturnURL и очищает его 
	static function redirect($default_url, $time=0)
	{
		if ( self::$url && self::$url!= $_SERVER['REQUEST_URI']) 
			redirect(self::$url, $time);
		else 
			redirect($default_url, $time);
		
		self::reset();
		
		if(!$time)exit;
	}

}

/*** 

***/

// javascript: history.go(-1) 

// echo "<script>location='{$_SERVER['HTTP_REFERER']}'</script>"; 

/***
Подобное решение:

<?php
// back.lib.php 

class TBack
{
var $History; // empty array for URI hashes
var $MaxHistoryDepth;
    function TBack() 
    {
        $this->MaxHistoryDepth = 15;
    } // end of constructor
    function AddUri($uri)
    {
        if(!array_key_exists(sha1($uri), $this->History)) {
            $this->History[sha1($uri)]=$uri;
            if(count($this->History)>$this->MaxHistoryDepth) {
                array_shift($this->History);
                };
            };
    }// end of Add Uri
    function GetUri($key)
    {
        if(!empty($this->History)) {
            return $this->History[$key];
            } else {
            return NULL;
            };
    }// end of Get Uri
}; // end of TBack
function BackThis()
{
    return sha1($_SERVER['REQUEST_URI']);
}; // end of Back This
?>


В коде непосредственно страницы

код PHP
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
include('libs/back.lib.php'); // обязательно должно стоять до session_start();
session_start();
if(!isset($_SESSION['bck'])) {
    $_SESSION['bck'] = new TBack(); 
    };
$_SESSION['bck']->AddUri($_SERVER['REQUEST_URI']);
...
...
...
//Рисуем кнопку перехода на другую страницу
?>
 <a href='tramparam.php?back=<?php echo BackThis(); ?>'> Вперед куда-то там </a>
<?php
//Рисуем кнопку возврата Назад
?>
<a href='<?php $_SESSION['bck']->GetUri($_GET['back']);?>'> Назад </a>



***/